package jp.co.cos.ittrick.channel.service;

import java.util.Date;
import java.util.List;

import jp.co.cos.ittrick.channel.Constants;
import jp.co.cos.ittrick.channel.common.exception.DatastorePutException;
import jp.co.cos.ittrick.channel.common.exception.DoubleInsertException;
import jp.co.cos.ittrick.channel.meta.PageModelMeta;
import jp.co.cos.ittrick.channel.model.CategoryModel;
import jp.co.cos.ittrick.channel.model.ChannelModel;
import jp.co.cos.ittrick.channel.model.ChapterModel;
import jp.co.cos.ittrick.channel.model.PageModel;

import org.slim3.datastore.Datastore;
import org.slim3.memcache.Memcache;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Transaction;


public class PageService {

    /**
     * キーによるクラスの取得
     * @param pkKey
     * @return ChannelModel
     */
    public PageModel getPageByKey(int pageKey) {

        Key classPkKey = Datastore.createKey(PageModelMeta.get(), pageKey);

        // Memcache に存在した場合はMemcache内のmodelを返す
        PageModel pageModel = Memcache.get(classPkKey);
        if(pageModel != null) return pageModel;

        // DBから取得し、存在した場合はMemcacheに入れる
        pageModel = Datastore.getOrNull(PageModel.class, classPkKey);
        if(pageModel != null) Memcache.put(classPkKey, pageModel);

        return pageModel;
    }

    /**
     * Pageリストを取得（publicのみ 範囲指定）
     * @param offset
     *             ここから
     * @param limit
     *             ここまで
     * @return Pageリスト
     */
    public List<PageModel> getPageListOfLimit(int offset, int limit) {

        // Memcache に存在した場合はMemcache内のmodelを返す
        List<PageModel> pageList = Memcache.get(Constants.NEW_PAGE_LIST_MEMCACHE_KEY);
        if(pageList != null && pageList.size() > 0) return pageList;


        // DBから取得し、存在した場合はMemcacheに入れる
        PageModelMeta pageModelMeta = new PageModelMeta();
        pageList =
            Datastore
            .query(pageModelMeta)
            .filter(pageModelMeta.publicFlg.equal(true))
            .sort(pageModelMeta.publicDate.desc)
            .offset(offset)
            .limit(limit)
            .asList();

        ChapterService chapterService = new ChapterService();
        ChannelService channelService = new ChannelService();
        CategoryService categoryService = new CategoryService();

        for(PageModel pageModel: pageList) {
            // chapterModel の取得
            ChapterModel chapterModel =chapterService.getChapterByKey((int)pageModel.getChapterModelRef().getKey().getId());

            // channelModel の取得
            CategoryModel categoryModel = categoryService.getCategoryByKey((int)chapterModel.getCategoryModelRef().getKey().getId());
            ChannelModel channelModel = channelService.getChannelByKey(categoryModel.getChannelModelRef().getKey().getName());

            pageModel.pageUrlString = "<a href=\"/" + channelModel.getKeyString() + "/c" + chapterModel.getKeyString() + "/page" + pageModel.getKeyString() + ".html\">" + channelModel.getName() + pageModel.getName() + "</a>";
        }

        if(pageList != null && pageList.size() > 0) Memcache.put(Constants.NEW_PAGE_LIST_MEMCACHE_KEY, pageList);

        return pageList;
    }

    /**
     * Insert
     * @param pkKey
     * @param model
     * @return key
     * @throws DoubleInsertException
     * @throws DatastorePutException
     */
    public Key insert(PageModel model)
    throws DoubleInsertException, DatastorePutException {

        // キーの作成
        Key key = null;
        model.setLastmod(new Date());

        // insert
        Transaction tx = Datastore.beginTransaction();
        try {
            key = Datastore.put(tx, model);
            tx.commit();

            // 新記事リストのMemcacheを削除する
            Memcache.delete(Constants.NEW_PAGE_LIST_MEMCACHE_KEY);
        }
        catch (Exception e) {
            if (tx.isActive()) {
                tx.rollback();
            }
            throw new DatastorePutException();
        }

        return key;
    }


    /**
     * Update
     * @param model
     * @throws DatastorePutException
     */
    public void update(PageModel model) throws DatastorePutException {

        model.setLastmod(new Date());

        // Local Transaction の開始
        Transaction tx = Datastore.beginTransaction();

        try {
            // バージョンによる変更チェック
            Datastore.get(tx, PageModelMeta.get(), model.getKey(), model.getVersion());
            // 更新
            Datastore.put(tx, model);

            tx.commit();

            // Memcacheを削除する
            Memcache.delete(model.getKey());
            // 新記事リストのMemcacheを削除する
            Memcache.delete(Constants.NEW_PAGE_LIST_MEMCACHE_KEY);

        }catch (Exception e) {
            if (tx.isActive()) {
                tx.rollback();
            }
            throw new DatastorePutException();
        }
    }

    /**
     * 削除
     * @param serialPkKey
     * @param articleNum
     * @param articlePageNum
     * @throws Exception
     */
    public void delete(int pkKey) throws Exception {

        PageModel pageModel = getPageByKey(pkKey);
        Key pageKey = pageModel.getKey();

        // Local Transaction の開始
        Transaction tx = Datastore.beginTransaction();

        try {
            Datastore.delete(tx, pageKey);

            tx.commit();

        }catch (Exception e) {
            if (tx.isActive()) {
                tx.rollback();
            }
            throw e;
        }
    }

}
